package com.pingao.mp.handle;

import com.google.common.net.HttpHeaders;
import com.pingao.mp.utils.Constant;
import com.pingao.mp.utils.set.MapBuilder;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 异常统一处理
 */
@ControllerAdvice
public class ExceptionHandle {

    private final static Logger LOGGER = LoggerFactory.getLogger(ExceptionHandle.class);

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Object handle(Exception e) throws IOException {
        LOGGER.error(e.getMessage());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            throw new IOException("获取不到ServletRequestAttributes");
        }
        HttpServletResponse response = attributes.getResponse();
        if (response == null) {
            throw new IOException("获取不到输出流");
        }
        HttpServletRequest request = attributes.getRequest();
        String contextPath = request.getContextPath();
        String requestType = request.getHeader("X-Requested-With");//为null则是一般请求，不为空则为ajax请求，跨域ajax访问，该项为空，所以直接判断访问URL里包不包括【/api】，如果不包括，则输出js脚本，否则返回json错误数据
        StringBuffer url = request.getRequestURL();
        boolean b = url.toString().contains("/api");
        if (e instanceof AuthorizationException) {
            if (requestType != null || b) {
                //如果是异步请求，则返回错误信息
                MapBuilder<String, Object> map = new MapBuilder<>();
                if (e instanceof UnauthenticatedException) {
                    map.put(Constant.ApiMsg, "用户没有认证, 请重新登录").put(Constant.ApiStatus, false).put("exception", e.getMessage());
                } else if (e instanceof UnauthorizedException) {
                    map.put(Constant.ApiMsg, "没有权限访问该模块").put(Constant.ApiStatus, false).put("exception", e.getMessage());
                } else {
                    map.put(Constant.ApiMsg, e.getMessage()).put(Constant.ApiStatus, false).put("exception", e.getMessage());
                }
                return map.get();
            } else {
                //一般的请求
                response.setContentType("text/html;charset=utf-8");
                if (e instanceof UnauthenticatedException) {
                    //response.sendRedirect("/sys/user/login");//如果是一般的请求，没有认证或没有权限，则跳转到登录界面
                    response.getWriter().write("<script type='text/javascript'>top.location.replace('" + contextPath + "/sys/user/login');</script>");
                } else if (e instanceof UnauthorizedException) {
                    response.getWriter().write("<script type='text/javascript'>alert(\"没有权限访问该模块:" + e.getMessage() + "\");window.history.back();</script>");
                } else {
                    response.getWriter().write("<script type='text/javascript'>alert(\"" + e.getMessage() + "\");window.history.back();</script>");
                }
                return null;
            }
        } else {
            if (requestType != null || b) {
                //如果是异步请求，则返回错误信息
                MapBuilder<String, Object> map = new MapBuilder<>();
                map.put(Constant.ApiMsg, e.getMessage()).put(Constant.ApiStatus, false).put("exception", e.getMessage()).put("login", true);
                if (e.getMessage().contains("401")) {
                    map.put("login", false);
                }
                //解决抛出异常，导致不能跨域访问的问题
                if (response.getHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN) == null) {
                    response.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
                }
                return map.get();
            } else if (e instanceof MaxUploadSizeExceededException && url.toString().contains("/ckeditor")) {
                MapBuilder<String, Object> map = new MapBuilder<>();
                map.put("uploaded", 0);
                Map<String, Object> p = new HashMap<>();
                p.put("message", "上传的文件过大，请检查文件大小再次尝试");
                map.put("error", p);
                return map.get();
            } else {
                response.setContentType("text/html;charset=utf-8");
                response.getWriter().write("<script type='text/javascript'>window.location.href = \"" + contextPath + "/sys/error/500?message=" + e.getMessage() + "\";</script>");
            }
            return null;
        }
    }
}